/*
 * @Description: axios中间件（初始化和全局配置）
 * @Author: HuiSir<273250950@qq.com>
 * @Date: 2020-08-06 13:16:24
 * @LastEditTime: 2025-08-26 15:21:29
 */
import { ElMessage } from "element-plus";
import qs from "qs";
import axios from "axios";
import { showLoading } from "@/ui";
import { useGetters, useAdminStore } from "@/store";
import { project } from "@/init/config";
import { fieldMapping, JsonToFormData } from "./common";

/* eslint-disable */

/**
 * 接口请求头数据类型ContentType
 */
export const ContentType = {
  JSON: "application/json",
  FormData: "multipart/form-data",
  Urlencoded: "application/x-www-form-urlencoded",
};

/**
 * api请求ContentType => FormData传参预设
 */
export const FormDataSet = {
  headers: { "Content-Type": ContentType.FormData },
};

/**
 * 响应报错
 */
export const showReqErrorMsg = (errMsg?: any) => {
  const msg = (
    errMsg
      ? errMsg.includes("timeout")
        ? "请求超时"
        : errMsg
      : "[Request error]: 未知错误"
  ).toString();
  ElMessage.error(msg);
  console.error(msg);
};

/**
 * 响应报错默认返回值
 */
const errorResReturn = (errMsg?: any, code: string = "500"): ReqRes => {
  const message = (errMsg || "[Request error]: 未知错误").toString();
  return {
    ok: 0,
    message,
    data: null,
    code,
  };
};

//初始化
const Axios = axios.create({
  baseURL: __BASE_API__, //api路径
  withCredentials: true, // 跨域时允许设置cookie
  timeout: 10000, //超时
});

// token
let Token: string;
let Loading: any;

//请求前钩子
Axios.interceptors.request.use(
  (config: any) => {
    // 加载loading，默认无loading，可在fetchOptions中配置
    // loading可传字符串，用于提示内容
    const ld = config.fetchOptions?.loading;
    if (ld) {
      Loading = showLoading(typeof ld === "string" ? ld : undefined);
    }
    // 由于执行请求时token可能已经改变，故每次请求前都要重新获取token
    Token = useGetters().getToken;
    // 判断是否存在token，如果存在的话，则每个http header都加上token
    if (Token) {
      config.headers[project.token.key] = Token;
    }

    // 请求入参字段处理，放到数据格式处理前面，防止数据格式被调整
    requestFieldAlignment(config);

    // 数据格式动态处理，默认不处理为application/json
    if (config.data instanceof FormData) {
      config.headers["Content-Type"] = ContentType.FormData;
    } else if (config.contentType === "urlencoded") {
      config.data = qs.stringify(config.data); // 转换为urlencoded
      config.headers["Content-Type"] = ContentType.Urlencoded;
    }

    // 如果Content-Type被设置为multipart/form-data，而数据本身是json,则转换为formData
    if (
      config.headers["Content-Type"] === ContentType.FormData &&
      !(config.data instanceof FormData)
    ) {
      config.data = JsonToFormData(config.data);
    }

    return config;
  },
  (error) => {
    Loading?.close();
    console.error("[Request error]: " + error);
  }
);

//响应后钩子
Axios.interceptors.response.use(
  (response: any) => {
    // 关闭loading
    Loading?.close();

    // 对响应数据做些事
    if (response.status !== 200) {
      const msg = `[Request error ${response.status}]:${response.statusText}`;
      showReqErrorMsg(msg);
      return errorResReturn(msg, String(response.status));
    }

    if (!response.data) {
      showReqErrorMsg();
      return errorResReturn();
    }

    if (
      typeof response.data === "string" &&
      response.headers["content-type"].includes("application/json")
    ) {
      try {
        response.data = JSON.parse(response.data);
      } catch (error) {
        showReqErrorMsg(`[Request error]: ${error}`);
      }
    }

    // 登陆失效：弹出登录框
    if (
      response.data[project.responseFields.code] &&
      response.data[project.responseFields.code] ===
        project.responseBaseCode.loginInvalid
    ) {
      useAdminStore().LoginInvalid();
    }

    /**
     * 请求返回非成功code
     */
    if (
      response.data[project.responseFields.code] &&
      response.data[project.responseFields.code] !==
        project.responseBaseCode.success
    ) {
      const codeMsgSet =
        project.responseErrMsg[response.data[project.responseFields.code]];
      if (codeMsgSet) {
        showReqErrorMsg(codeMsgSet);
      } else {
        showReqErrorMsg(response.data[project.responseFields.message]);
      }
    }

    // 更新token
    const newToken = response.headers[project.token.key];
    if (newToken && newToken !== Token) {
      useAdminStore().setToken(newToken);
    }

    // 添加额外参数判断是否请求成功
    if (response.data.ok == void 0 && typeof response.data === "object") {
      response.data.ok =
        response.data &&
        response.data[project.responseFields.code] ===
          project.responseBaseCode.success
          ? 1
          : 0;
    }

    // 请求结果字段对齐
    responseFieldAlignment(response);

    return response.data;
  },
  (error) => {
    // 关闭loading
    Loading?.close();

    // 代码层面出错
    if (!error.response) {
      const msg = error.toString();
      //错误提示
      showReqErrorMsg(msg);
      return errorResReturn(msg);
    }
    // 后端返回异常
    const { status, statusText } = error.response;
    // 若这里响应码为403，则改变登陆状态，弹出登录框
    if (status === 403) {
      useAdminStore().LoginInvalid();
    }

    const msg = `${status}: ${statusText}（${error.response.config.url}）`;
    showReqErrorMsg(msg);
    return errorResReturn(msg, String(status));
  }
);

/**
 * 请求入参字段对齐
 */
function requestFieldAlignment(requestConfig: {
  data?: any;
  params?: any;
  headers: any;
}) {
  if (requestConfig.data) {
    const isJson =
      typeof requestConfig.data === "string" &&
      requestConfig.headers["Content-Type"].includes("json");

    // json
    const parseData = isJson
      ? JSON.parse(requestConfig.data)
      : requestConfig.data;

    if (Object.prototype.toString.call(parseData) === "[object Object]") {
      let temp = false;

      fieldMapping({
        data: parseData,
        fieldsMap: project.requestFields,
        reverse: true,
      });

      if (temp) {
        requestConfig.data = isJson ? JSON.stringify(parseData) : parseData;
      }
    }
  }

  if (
    requestConfig.params &&
    Object.prototype.toString.call(requestConfig.params) ===
      "[object Object]" &&
    Object.keys(requestConfig.params).length
  ) {
    fieldMapping({
      data: requestConfig.params,
      fieldsMap: project.requestFields,
      reverse: true,
    });
  }
}

/**
 * 请求结果字段对齐
 */
function responseFieldAlignment(response: { data: any }) {
  // 父对象
  fieldMapping({
    data: response.data,
    fieldsMap: project.responseFields,
  });

  // data子对象
  fieldMapping({
    data: response.data.data,
    fieldsMap: project.responseFields,
  });
}

export default Axios;
